package com.fsm.common.tools.util;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;

/**
 * 时间工具类
 */
public class DateUtils {

    /**
     * date转String
     *
     * @param date 时间
     * @param type 时间格式，如：yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String dateTurnString(Date date, String type) throws Exception {
        SimpleDateFormat formatter = new SimpleDateFormat(type);
        return formatter.format(date);
    }

    /**
     * String转date
     *
     * @param dateStr 时间
     * @param type 时间格式，如：yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static Date stringTurnDate(String dateStr, String type) throws Exception {
        SimpleDateFormat formatter = new SimpleDateFormat(type);
        return formatter.parse(dateStr);
    }

    /**
     * 比较两个时间的大小
     *
     * @param date1 时间1
     * @param date2 时间2
     * @return
     */
    public static boolean checkTwoDate(Date date1, Date date2) {
        if (date1.before(date2)) {
            //表示date1小于date2
            return true;
        } else {
            //表示date1大于date2
            return false;
        }
    }

    /**
     * 获取 两个时间内 全部日期
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return
     */
    public static List<String> getAscDateList(Date start, Date end) {
        List<String> result = new ArrayList<>();
        LocalDate startDate = start.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endDate = end.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        if (endDate.compareTo(startDate) < 0) {
            return result;
        }
        while (true) {
            result.add(startDate.toString());
            if (startDate.compareTo(endDate) >= 0) {
                break;
            }
            startDate = startDate.plusDays(1);
        }
        return result;
    }

    /**
     * 获取某时间的后几天时间
     * @param date 时间
     * @param num 几天
     * @return
     */
    public static Date getNextDay(Date date, Integer num){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, num);
        return calendar.getTime();
    }

    /**
     * 获取某时间的前几天时间
     * @param date 时间
     * @param num 几天
     * @return
     */
    public static Date getLastDay(Date date, Integer num){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, -num);
        return calendar.getTime();
    }

    /**
     * 获取某时间的后几周时间
     *
     * @param date 日期
     * @param num 几周
     * @return
     */
    public static Date getNextWeek(Date date, Integer num) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, num*7);
        Date m = c.getTime();
        String mon = format.format(m);
        return stringTurnDate(mon,"yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取某时间的上几周时间
     *
     * @param date 日期
     * @param num 几周
     * @return
     */
    public static Date getLastWeek(Date date, Integer num) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, -num*7);
        Date m = c.getTime();
        String mon = format.format(m);
        return stringTurnDate(mon,"yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取某时间的几年后时间
     *
     * @param date 日期
     * @param num 几年
     * @return
     */
    public static Date getNextYear(Date date, Integer num) throws Exception {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, num);
        return c.getTime();
    }

    /**
     * 获取某时间的几年前时间
     *
     * @param date 日期
     * @param num 几年
     * @return
     */
    public static Date getLastYear(Date date, Integer num) throws Exception {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, -num);
        return c.getTime();
    }

    /**
     * 判断两个时间相差多少秒
     *
     * @param date1 时间1
     * @param date2 时间2
     * @return
     */
    public static int getTwoDateSecond(Date date1, Date date2) throws Exception {
        long time1 = date1.getTime();
        long time2 = date2.getTime();
        long diff = time2 - time1;
        return (int)(diff / 1000);
    }
    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意三个参数的时间格式要一致
     * @param nowTime
     * @param startTime
     * @param endTime
     * @return 在时间段内返回true，不在返回false
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if(startTime.getTime() <= nowTime.getTime() && endTime.getTime() >= nowTime.getTime()){
            return true;
        }
        return false;
    }

    /**
     * 获取两个日期之间的月份
     *
     * @param startDate 开始时间
     * @param endDate 结束时间
     * @return
     */
    public static List<String> findMonthsStrTime(Date startDate, Date endDate) {
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            // 获取开始年份和开始月份
            int startYear = calendar.get(Calendar.YEAR);
            int startMonth = calendar.get(Calendar.MONTH);
            // 获取结束年份和结束月份
            calendar.setTime(endDate);
            int endYear = calendar.get(Calendar.YEAR);
            int endMonth = calendar.get(Calendar.MONTH);
            //
            List<String> list = new ArrayList<String>();
            for (int i = startYear; i <= endYear; i++) {
                String date = "";
                if (startYear == endYear) {
                    for (int j = startMonth; j <= endMonth; j++) {
                        if (j < 9) {
                            date = i + "-0" + (j + 1);
                        } else {
                            date = i + "-" + (j + 1);
                        }
                        list.add(date);
                    }
                } else {
                    if (i == startYear) {
                        for (int j = startMonth; j < 12; j++) {
                            if (j < 9) {
                                date = i + "-0" + (j + 1);
                            } else {
                                date = i + "-" + (j + 1);
                            }
                            list.add(date);
                        }
                    } else if (i == endYear) {
                        for (int j = 0; j <= endMonth; j++) {
                            if (j < 9) {
                                date = i + "-0" + (j + 1);
                            } else {
                                date = i + "-" + (j + 1);
                            }
                            list.add(date);
                        }
                    } else {
                        for (int j = 0; j < 12; j++) {
                            if (j < 9) {
                                date = i + "-0" + (j + 1);
                            } else {
                                date = i + "-" + (j + 1);
                            }
                            list.add(date);
                        }
                    }

                }
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据年月获取月初第一天日期
     * @param year 年
     * @param month 月
     * @param format 时间格式，如：yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getFirstDay(int year,int month,String format) {
        Calendar cale = Calendar.getInstance();
        cale.set(Calendar.YEAR,year);    //赋值年份
        cale.set(Calendar.MONTH, month-1);//赋值月份
        int lastDay = cale.getActualMinimum(Calendar.DAY_OF_MONTH);//获取月最大天数
        cale.set(Calendar.DAY_OF_MONTH, lastDay);//设置日历中月份的最大天数
        SimpleDateFormat sdf = new SimpleDateFormat(format);//格式化日期yyyy-MM-dd
        String lastDayOfMonth = sdf.format(cale.getTime());
        return lastDayOfMonth;
    }

    /**
     * 根据年月获取月末最后一天日期
     * @param year 年
     * @param month 月
     * @param format 时间格式，如：yyyy-MM-dd HH:mm:ss
     */
    public static String getLastDay(int year,int month,String format) {
        Calendar cale = Calendar.getInstance();
        cale.set(Calendar.YEAR,year);//赋值年份
        cale.set(Calendar.MONTH, month-1);//赋值月份
        int lastDay = cale.getActualMaximum(Calendar.DAY_OF_MONTH);//获取月最大天数
        cale.set(Calendar.DAY_OF_MONTH, lastDay);//设置日历中月份的最大天数
        SimpleDateFormat sdf = new SimpleDateFormat(format);    //格式化日期yyyy-MM-dd
        String lastDayOfMonth = sdf.format(cale.getTime());
        return lastDayOfMonth;
    }

    /**
     * 根据出生日期计算年龄
     * @param birthDate 出生时间
     * @return
     */
    public static Integer getAge(Date birthDate){
        // 当前日历
        Calendar nowCalendar = Calendar.getInstance();
        // 生日大于当前日期
        if (nowCalendar.before(birthDate)) {
            throw new IllegalArgumentException("The birth date is before current time, it's unbelievable");
        }
        // 当前年月日
        int yearNow = nowCalendar.get(Calendar.YEAR);
        int monthNow = nowCalendar.get(Calendar.MONTH);
        int dayNow = nowCalendar.get(Calendar.DAY_OF_MONTH);
        // 出生日期年月日
        Calendar birthCalendar = Calendar.getInstance();
        birthCalendar.setTime(birthDate);
        int yearBirth = birthCalendar.get(Calendar.YEAR);
        int monthBirth = birthCalendar.get(Calendar.MONTH);
        int dayBirth = birthCalendar.get(Calendar.DAY_OF_MONTH);
        // 粗计算年龄
        int age = yearNow - yearBirth;
        // 当前月份小于出生月份年龄减一
        if (monthNow < monthBirth) { age--; }
        // 当前月份等于出生月份，日小于生日年龄减一
        else if (monthNow == monthBirth && dayNow < dayBirth) { age--; }
        // 返回年龄值
        return age;
    }

    /**
     * 归零时分秒
     * @param date 时间
     * @return
     */
    public static Date returnZero(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //归零时分秒
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }

    /**
     * 获取后几天的日期
     * @param date 时间
     * @param day 几天
     * @return
     */
    public static Date getTomorrow(Date date ,Integer day){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, day);
        //归零时分秒
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }

    /**
     * 获取时间是周几
     * @param date 时间
     * @return 1-7
     */
    public static Integer getWeek(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int week = calendar.get(Calendar.DAY_OF_WEEK);
        week -= 1;
        if(week == 0){
            week = 7;
        }
        return week;
    }

    /**
     * 获取当月的开始时间和结束时间
     * @return
     */
    public static Map<String,Date> getThisMonth() throws Exception {
        Calendar calendar = Calendar.getInstance();

        int currentMonth = calendar.get(Calendar.MONTH) + 1;

        calendar.set(Calendar.DAY_OF_MONTH, 1);
        Date firstDayOfMonth = calendar.getTime();

        calendar.add(Calendar.MONTH, 1);

        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date lastDayOfMonth = calendar.getTime();

        Map<String,Date> map = new HashMap<>();
        map.put("beginTime",firstDayOfMonth);
        map.put("endTime",lastDayOfMonth);
        return map;
    }

    /**
     * 获取上月的开始时间和结束时间
     * @return
     */
    public static Map<String,Date> getLastMonth() throws Exception {
        Calendar calendar = Calendar.getInstance();

        int currentMonth = calendar.get(Calendar.MONTH);

        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        Date firstDayOfMonth = calendar.getTime();

        calendar.add(Calendar.MONTH, 1);

        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date lastDayOfMonth = calendar.getTime();

        Map<String,Date> map = new HashMap<>();
        map.put("beginTime",firstDayOfMonth);
        map.put("endTime",lastDayOfMonth);
        return map;
    }

    /**
     * 获取下月的开始时间和结束时间
     * @return
     */
    public static Map<String,Date> getNextMonth() throws Exception {
        Calendar calendar = Calendar.getInstance();

        int currentMonth = calendar.get(Calendar.MONTH) + 2;

        calendar.add(Calendar.MONTH, +1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        Date firstDayOfMonth = calendar.getTime();

        calendar.add(Calendar.MONTH, 1);

        calendar.add(Calendar.DAY_OF_MONTH, -1);
        Date lastDayOfMonth = calendar.getTime();

        Map<String,Date> map = new HashMap<>();
        map.put("beginTime",firstDayOfMonth);
        map.put("endTime",lastDayOfMonth);
        return map;
    }

    /**
     * 获取两个时间的毫秒数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    public static Integer getMinuteDifference(Date startTime, Date endTime){
        long diff = endTime.getTime() - startTime.getTime();
        long diffMinutes = diff / (60 * 1000);
        return Math.toIntExact(diffMinutes);
    }

}
